home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 June / MacFormat 25.iso / Shareware City / Developers / OutOfPhase1.1 Source / OutOfPhase Folder / Level 0 Macintosh 01Jan95 / MyMalloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-01  |  23.0 KB  |  619 lines  |  [TEXT/KAHL]

  1. /* MyMalloc.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Debug.h"
  21. #include "Audit.h"
  22. #include "Definitions.h"
  23.  
  24. #ifdef THINK_C
  25.     #pragma options(pack_enums)
  26. #endif
  27. #include <Memory.h>
  28. #include <Errors.h>
  29. #include <Files.h>
  30. #ifdef THINK_C
  31.     #pragma options(!pack_enums)
  32. #endif
  33.  
  34. #include "MyMalloc.h"
  35.  
  36.  
  37. /* limitations: */
  38. /*  - total address space hasn't been tested for more than 24 bits. */
  39. /*  - blocks can't be more than 2^BOUNDARY - sizeof(BlockRec) blocks large */
  40. /*  - only works with flat addressing */
  41.  
  42.  
  43. /* alignment MUST be power of 2.  this cleverly aligns to long integers or */
  44. /* pointers, whichever is larger */
  45. #define ALIGNMENT ((sizeof(long) > sizeof(void*)) ? sizeof(long) : sizeof(void*))
  46.  
  47. /* provide 4 bits of correction (so that requested block sizes can be up to */
  48. /* 15 bytes smaller than the actual heap block allocated.  Hopefully this will work */
  49. /* even if unsigned longs are 64 bits. */
  50. #define BOUNDARY ((8 * sizeof(unsigned long)) - 4)
  51.  
  52. /* this macro calculates the largest possible size a user could request and */
  53. /* not break the allocator by finding out what the largest block size is and */
  54. /* subtracting the header to find out the content size.  Actually, this will be */
  55. /* a bit smaller, since not of all the header is actually present when the */
  56. /* block is allocated (there is some overlap between header and data area) */
  57. #define MEMBLOCKLIMIT ((1UL << BOUNDARY) - sizeof(BlockRec))
  58.  
  59. /* this defines the smallest amount of memory that will be requested from the */
  60. /* system if there is not enough already in the heap to satisfy a request. */
  61. /* (for debugging purposes, we make it ridiculously small.)  Make sure that */
  62. /* this is an aligned value!  see notes about exo-core below in the code. */
  63. #if DEBUG
  64.     #define MINMORECORESIZE (16L)
  65.     #define MINEXOCORESIZE (16L)
  66. #else
  67.     #define MINMORECORESIZE (4096L)
  68.     #define MINEXOCORESIZE (262144L)
  69. #endif
  70.  
  71. /* amount of space reserved below our first handle for system objects */
  72. #define LOWMEMRESERVEDSIZE (49152L)
  73.  
  74. /* when the local heap runs out of space, we try to allocate as much as possible from */
  75. /* it so that we don't waste that space.  this is done in increments of the following */
  76. #define LOCALINCREMENTSIZE (4096L)
  77.  
  78. /* encode the total size of a block and the number of bytes less the requested */
  79. /* size actually was into a single unsigned long word, so that we don't have */
  80. /* to waste any more bytes than we need.  This is done by remembering the total */
  81. /* allocated size and the number of bytes more than the requested size that the */
  82. /* total size was. */
  83. #define SIZEENCODE(size,correction) (((correction) << BOUNDARY) | (size))
  84.  
  85. /* find out what size the user requested by subtracting the amount of extra */
  86. /* bytes from the total size of the block */
  87. #define DECODEREQUESTEDSIZE(composite) (((composite) & ((1UL << BOUNDARY) - 1))\
  88.                     - (((composite) >> BOUNDARY) & 0x0f))
  89.  
  90. /* find out what the total size allocated was */
  91. #define DECODETOTALSIZE(composite) ((composite) & ((1UL << BOUNDARY) - 1))
  92.  
  93.  
  94. /* this structure defines the fields for a block header */
  95. typedef struct BlockRec
  96.     {
  97.         /* BlockSize contains the size of a block, which has differing meanings depending */
  98.         /* on whether the block is free or used.  If the block is free, then it is simply */
  99.         /* the total number of bytes in the block.  If the block is used, then it is */
  100.         /* an encoded size, with the block's total size & the correction for determining */
  101.         /* how much was requested when the block was allocated. */
  102.         unsigned long                BlockSize;
  103.         /* pointer to Next block in the free list is only used when block is free.  If */
  104.         /* block is allocated, then the data starts at the first byte of Next. */
  105.         /* That last bit is important because it allows us to adjust the number and */
  106.         /* size of header fields before the Next for debugging purposes. */
  107.         struct BlockRec*        Next;
  108.     } BlockRec;
  109.  
  110.  
  111. /* list of blocks that are free, linked through the Next field */
  112. static BlockRec*            FreeList = NIL;
  113.  
  114. /* last macintosh handle allocated.  when we need morecore, we try to extend this */
  115. /* before allocating another handle so that we can keep all storage contiguous. */
  116. static char**                    LastHandleAllocated = NIL;
  117.  
  118. /* this flag is True if LastHandleAllocated is local to the heap, or False if */
  119. /* it is allocated outside of our heap. */
  120. static MyBoolean            LastHandleIsLocal;
  121.  
  122. /* debugging variable for detecting memory leaks and multiple releases. */
  123. EXECUTE(static long        AllocationCount = 0;)
  124.  
  125.  
  126. /* initialize the memory allocator. */
  127. MyBoolean        InitializeMyMalloc(void)
  128.     {
  129.         char**        Temp;
  130.  
  131.         /* since we stick a handle in the heap and lock it, but try to resize it, */
  132.         /* we want to reserve some space below it for static objects. */
  133.         ReserveMem(LOWMEMRESERVEDSIZE);
  134.         Temp = NewHandle(LOWMEMRESERVEDSIZE);
  135.         if (Temp == NIL)
  136.             {
  137.                 return False;
  138.             }
  139.         HLock(Temp);
  140.         /* now allocate an initial handle for our heap thing */
  141.         LastHandleAllocated = NewHandle(0);
  142.         if (LastHandleAllocated == NIL)
  143.             {
  144.                 return False;
  145.             }
  146.         HLock(LastHandleAllocated);
  147.         LastHandleIsLocal = True;
  148.         /* finally, dispose of the low memory space to free it up for the system */
  149.         DisposeHandle(Temp);
  150.         return True;
  151.     }
  152.  
  153.  
  154. /* allocate a new block of memory.  If there is no free block large enough, the */
  155. /* heap is extended.  If the block size is greater than MINMORECORESIZE, then */
  156. /* a system block the size of the block will be allocated, otherwise a system */
  157. /* block of MINMORECORESIZE bytes will be allocated. */
  158. void*                BlockNew(long RequestedBlockSize)
  159.     {
  160.         BlockRec*                        Scan;
  161.         BlockRec*                        Lag;
  162.         unsigned long                Extra;
  163.         unsigned long                TotalSize;
  164.         void*                                ReturnValue;
  165.         long                                OSRequestedSize;
  166.         char**                            NewMemHandle;
  167.         MyBoolean                        NewMemHandleIsLocal;
  168.  
  169.         APRINT(("+BlockNew %l",RequestedBlockSize));
  170.         ERROR((RequestedBlockSize < 0) || (RequestedBlockSize > MEMBLOCKLIMIT),
  171.             PRERR(ForceAbort,"BlockNew:  allocation block size is out of range"));
  172.      TryAgainPoint:
  173.         Scan = FreeList;
  174.         Lag = NIL;
  175.         /* (BlockSize + Extra) % ALIGNMENT must == 0 */
  176.         Extra = (ALIGNMENT - 1) - ((RequestedBlockSize + 3) & (ALIGNMENT - 1));
  177.         /* figure out amount of extra space to add to request to get the actual */
  178.         /* block size we need to allocate.  The funny bit on the end figures out */
  179.         /* how many bytes are in the USED block's header.  (the free block's header */
  180.         /* has sizeof(BlockRec) bytes in it, but we can't use this since we overwrite */
  181.         /* the Next field, thus making the used header smaller.) */
  182.         TotalSize = RequestedBlockSize + Extra
  183.             + (long)((char*)&(((BlockRec*)NIL)->Next) - (char*)NIL);
  184.         if (TotalSize < sizeof(BlockRec))
  185.             {
  186.                 /* for tiny blocks, we must be sure we can always free the block */
  187.                 TotalSize = sizeof(BlockRec);
  188.             }
  189.         /* scan through list of free blocks to find one that's big enough */
  190.         while (Scan != NIL)
  191.             {
  192.                 if (Scan->BlockSize >= TotalSize)
  193.                     {
  194.                         /* found a big enough block */
  195.                         if (Scan->BlockSize < TotalSize + sizeof(BlockRec))
  196.                             {
  197.                                 /* block is too small to split -- take the whole thing */
  198.                                 /* eliminate this block from the free list */
  199.                                 if (Lag != NIL)
  200.                                     {
  201.                                         Lag->Next = Scan->Next;
  202.                                     }
  203.                                  else
  204.                                     {
  205.                                         FreeList = Scan->Next;
  206.                                     }
  207.                                 /* adjust block size of Scan */
  208.                                 /* since we are allocating the whole block, we use [preserve] the */
  209.                                 /* block's original size (see below) */
  210.                                 ERROR(DECODETOTALSIZE((unsigned long)SIZEENCODE(Scan->BlockSize,
  211.                                     Scan->BlockSize - RequestedBlockSize))
  212.                                     - DECODEREQUESTEDSIZE((unsigned long)SIZEENCODE(Scan->BlockSize,
  213.                                     Scan->BlockSize - RequestedBlockSize))
  214.                                     != Scan->BlockSize - RequestedBlockSize,PRERR(ForceAbort,
  215.                                     "BlockNew:  not enough bits specified for size correction"));
  216.                                 Scan->BlockSize = SIZEENCODE(Scan->BlockSize,
  217.                                     Scan->BlockSize - RequestedBlockSize);
  218.                                 /* set up return value */
  219.                                 ReturnValue = (void*)&(Scan->Next);
  220.                             }
  221.                          else
  222.                             {
  223.                                 /* block is big enough to be split */
  224.                                 /* first, make a new block header where the second part of the */
  225.                                 /* block starts, and set up the fields in the header */
  226.                                 if (Lag != NIL)
  227.                                     {
  228.                                         Lag->Next = (BlockRec*)((char*)Scan + TotalSize);
  229.                                         /* pointer update first! (else for 0 length blocks, it will */
  230.                                         /* get overwritten) */
  231.                                         Lag->Next->Next = Scan->Next;
  232.                                         Lag->Next->BlockSize = Scan->BlockSize - TotalSize;
  233.                                     }
  234.                                  else
  235.                                     {
  236.                                         FreeList = (BlockRec*)((char*)Scan + TotalSize);
  237.                                         /* pointer update first! (else for 0 length blocks, it will */
  238.                                         /* get overwritten) */
  239.                                         FreeList->Next = Scan->Next;
  240.                                         FreeList->BlockSize = Scan->BlockSize - TotalSize;
  241.                                     }
  242.                                 /* construct the header for the current block */
  243.                                 /* since we are splitting the block, we use the plopped off size */
  244.                                 /* so that both block's sizes add up to the original (see above) */
  245.                                 ERROR(DECODETOTALSIZE((unsigned long)SIZEENCODE(TotalSize,TotalSize
  246.                                     - RequestedBlockSize))
  247.                                     - DECODEREQUESTEDSIZE((unsigned long)SIZEENCODE(TotalSize,TotalSize
  248.                                     - RequestedBlockSize))
  249.                                     != TotalSize - RequestedBlockSize,PRERR(ForceAbort,
  250.                                     "BlockNew:  not enough bits specified for size correction"));
  251.                                 Scan->BlockSize = SIZEENCODE(TotalSize,TotalSize - RequestedBlockSize);
  252.                                 /* set up the return value */
  253.                                 ReturnValue = (void*)&(Scan->Next);
  254.                             }
  255.                         EXECUTE(CheckHeap());
  256.                         EXECUTE(AllocationCount += 1;)
  257.                         APRINT(("-BlockNew %r",ReturnValue));
  258.                         return ReturnValue;
  259.                     }
  260.                 /* this block wasn't big enough -- try the next one */
  261.                 Lag = Scan;
  262.                 Scan = Scan->Next;
  263.             }
  264.  
  265.         /* no memory on free list -- try to get more memory from system */
  266.         APRINT((" MoreCore"));
  267.         if (TotalSize > MINMORECORESIZE)
  268.             {
  269.                 /* no alignment worries since TotalSize is made to be aligned above */
  270.                 OSRequestedSize = TotalSize;
  271.             }
  272.          else
  273.             {
  274.                 OSRequestedSize = MINMORECORESIZE;
  275.             }
  276.  
  277.         /* first, try to grow the last handle we allocated */
  278.         if (LastHandleAllocated != NIL)
  279.             {
  280.                 long                OldHandleSize;
  281.  
  282.                 OldHandleSize = GetHandleSize(LastHandleAllocated);
  283.                 SetHandleSize(LastHandleAllocated,OldHandleSize + OSRequestedSize);
  284.                 if (MemError() == noErr)
  285.                     {
  286.                         /* set up the header for this new block, as if it were used */
  287.                         ERROR(DECODETOTALSIZE((unsigned long)SIZEENCODE(OSRequestedSize,
  288.                             sizeof(BlockRec))) - DECODEREQUESTEDSIZE((unsigned long)SIZEENCODE(
  289.                             OSRequestedSize,sizeof(BlockRec))) != sizeof(BlockRec),PRERR(ForceAbort,
  290.                             "BlockNew:  not enough bits specified for size correction"));
  291.                         (*(BlockRec*)(*(char**)LastHandleAllocated + OldHandleSize)).BlockSize
  292.                             = SIZEENCODE(OSRequestedSize,sizeof(BlockRec));
  293.                         /* release it with the normal block release routine */
  294.                         EXECUTE(AllocationCount += 1;) /* offset the effect of the following release */
  295.                         BlockRelease((void*)&((*(BlockRec*)((char*)StripAddress(
  296.                             *LastHandleAllocated) + OldHandleSize)).Next));
  297.                         /* try to allocate the block now */
  298.                         goto TryAgainPoint;
  299.                     }
  300.                  else
  301.                     {
  302.                         /* if the block couldn't be resized, then resize it up as large as */
  303.                         /* we can make it, if it's inside the application's heap.  this makes */
  304.                         /* sure we don't lose any space from the local heap. */
  305.                         if (LastHandleIsLocal)
  306.                             {
  307.                                 long                        AddedSpaceCounter;
  308.                                 OSErr                        ErrorThang;
  309.  
  310.                                 AddedSpaceCounter = 0;
  311.                                 do
  312.                                     {
  313.                                         SetHandleSize(LastHandleAllocated,GetHandleSize(LastHandleAllocated)
  314.                                             + LOCALINCREMENTSIZE);
  315.                                         ErrorThang = MemError();
  316.                                         if (ErrorThang == noErr)
  317.                                             {
  318.                                                 AddedSpaceCounter += LOCALINCREMENTSIZE;
  319.                                             }
  320.                                     } while (ErrorThang == noErr);
  321.                                 /* now incorporate new block, but only if there actually is one */
  322.                                 if (AddedSpaceCounter > 0)
  323.                                     {
  324.                                         /* set up the header for this new block, as if it were used */
  325.                                         ERROR(DECODETOTALSIZE((unsigned long)SIZEENCODE(AddedSpaceCounter,
  326.                                             sizeof(BlockRec))) - DECODEREQUESTEDSIZE(
  327.                                             (unsigned long)SIZEENCODE(AddedSpaceCounter,sizeof(BlockRec)))
  328.                                             != sizeof(BlockRec),PRERR(ForceAbort,"BlockNew:  not enough "
  329.                                             "bits specified for size correction"));
  330.                                         (*(BlockRec*)(*(char**)LastHandleAllocated + OldHandleSize))
  331.                                             .BlockSize = SIZEENCODE(AddedSpaceCounter,sizeof(BlockRec));
  332.                                         /* release it with the normal block release routine */
  333.                                         EXECUTE(AllocationCount += 1;) /* offset the effect of the release */
  334.                                         BlockRelease((void*)&((*(BlockRec*)((char*)StripAddress(
  335.                                             *LastHandleAllocated) + OldHandleSize)).Next));
  336.                                         /* prevent us from trying this little stunt again. */
  337.                                         LastHandleIsLocal = False;
  338.                                         /* try to allocate the block now */
  339.                                         goto TryAgainPoint;
  340.                                 }
  341.                             }
  342.                     }
  343.             }
  344.  
  345.         ERROR(MINEXOCORESIZE < MINMORECORESIZE,PRERR(ForceAbort,
  346.             "BlockNew:  MINEXOCORESIZE < MINMORECORESIZE"));
  347.         if (OSRequestedSize < LOWMEMRESERVEDSIZE + (32 * ALIGNMENT))
  348.             {
  349.                 /* keep from clobbering the reserved space that we so carefully set aside */
  350.                 OSRequestedSize = LOWMEMRESERVEDSIZE + (32 * ALIGNMENT);
  351.             }
  352.         ReserveMem(OSRequestedSize);
  353.         NewMemHandle = NewHandle(OSRequestedSize);
  354.         NewMemHandleIsLocal = True;
  355. #if !DEBUG  /* when debugging, we stay in local heap */
  356.         if (NewMemHandle == NIL)
  357.             {
  358.                 OSErr                Error;
  359.  
  360.                 if (OSRequestedSize < MINEXOCORESIZE)
  361.                     {
  362.                         /* if we allocate outside of our heap, we will grab larger */
  363.                         /* blocks of memory since we have less control over what may */
  364.                         /* get allocated on top of us.  hopefully this will reduce fragmentation */
  365.                         /* of blocks outside of the heap */
  366.                         OSRequestedSize = MINEXOCORESIZE;
  367.                     }
  368.                 NewMemHandle = TempNewHandle(OSRequestedSize,&Error);
  369.                 NewMemHandleIsLocal = False;
  370.             }
  371. #endif
  372.         if (NewMemHandle != NIL)
  373.             {
  374.                 ERROR((((unsigned long)(*NewMemHandle) & (ALIGNMENT - 1)) != 0),
  375.                     PRERR(ForceAbort,"Hey! The memory manager's block is not aligned!"));
  376.                 /* make sure the mac doesn't move our memory */
  377.                 HLock(NewMemHandle);
  378.                 /* set up the header for this new block, as if it were used */
  379.                 ERROR(DECODETOTALSIZE((unsigned long)SIZEENCODE(OSRequestedSize,
  380.                     sizeof(BlockRec))) - DECODEREQUESTEDSIZE((unsigned long)SIZEENCODE(
  381.                     OSRequestedSize,sizeof(BlockRec))) != sizeof(BlockRec),PRERR(ForceAbort,
  382.                     "BlockNew:  not enough bits specified for size correction"));
  383.                 (**(BlockRec**)NewMemHandle).BlockSize
  384.                     = SIZEENCODE(OSRequestedSize,sizeof(BlockRec));
  385.                 /* release it with the normal block release routine */
  386.                 EXECUTE(AllocationCount += 1;) /* offset the effect of the following release */
  387.                 BlockRelease((void*)StripAddress(&((**(BlockRec**)NewMemHandle).Next)));
  388.                 /* remember the block's location so we can try to grow it later */
  389.                 LastHandleAllocated = NewMemHandle;
  390.                 LastHandleIsLocal = NewMemHandleIsLocal;
  391.                 /* try to allocate the block now */
  392.                 goto TryAgainPoint;
  393.             }
  394.         EXECUTE(CheckHeap());
  395.         APRINT(("-BlockNew NIL"));
  396.         return NIL;
  397.     }
  398.  
  399.  
  400. /* this routine releases blocks back to the free list and unifies them with */
  401. /* adjacent blocks if possible.  It keeps the free list in ascending */
  402. /* sorted order to make scanning for adjacent blocks more efficient. */
  403. void                BlockRelease(void* Block)
  404.     {
  405.         BlockRec*        Scan;
  406.         BlockRec*        Lag;
  407.         BlockRec*        OurNewBlock;
  408.  
  409.         /* this first thing is an ugly but portable way of treating *Block as the */
  410.         /* 'Next' field of a BlockRec and finding out where the BlockRec begins */
  411.         OurNewBlock = (BlockRec*)((char*)Block
  412.             - ((char*)&(((BlockRec*)NIL)->Next) - (char*)NIL));
  413.         APRINT(("+BlockRelease %r (size %l)",Block,DECODETOTALSIZE(OurNewBlock->BlockSize)));
  414.         /* adjust block's header so that it is free */
  415.         OurNewBlock->BlockSize = DECODETOTALSIZE(OurNewBlock->BlockSize);
  416.         /* scan the free list looking for items that can be appended / prepended to block */
  417.         Lag = NIL;
  418.         Scan = FreeList;
  419.         while ((Scan != NIL) && (Scan < OurNewBlock))
  420.             {
  421.                 /* searching so that Lag is before OurNewBlock and Scan is after it */
  422.                 Lag = Scan;
  423.                 Scan = Scan->Next;
  424.             }
  425.         /* now, scan is either NIL or the block right after this block. */
  426.         /* now trying to put block into the list */
  427.         OurNewBlock->Next = Scan;
  428.         if (Lag != NIL)
  429.             {
  430.                 Lag->Next = OurNewBlock;
  431.             }
  432.          else
  433.             {
  434.                 FreeList = OurNewBlock;
  435.             }
  436.         /* first, try to coalesce block with the one before it */
  437.         if (Lag != NIL)
  438.             {
  439.                 if ((char*)Lag + Lag->BlockSize == (char*)OurNewBlock)
  440.                     {
  441.                         /* if we can coalesce, dump block & add to Lag's size */
  442.                         Lag->BlockSize += OurNewBlock->BlockSize;
  443.                         Lag->Next = OurNewBlock->Next;
  444.                         OurNewBlock = Lag;
  445.                     }
  446.             }
  447.         /* now, try to coalesce block with the one after it */
  448.         if (Scan != NIL)
  449.             {
  450.                 if ((char*)OurNewBlock + OurNewBlock->BlockSize == (char*)Scan)
  451.                     {
  452.                         OurNewBlock->BlockSize += Scan->BlockSize;
  453.                         OurNewBlock->Next = Scan->Next;
  454.                     }
  455.             }
  456.         EXECUTE(CheckHeap());
  457.         EXECUTE(AllocationCount -= 1;)
  458.         APRINT(("-BlockRelease"));
  459.     }
  460.  
  461.  
  462. /* decode and return the size of an allocated block */
  463. long                BlockSize(void* Block)
  464.     {
  465.         BlockRec*        TrueBlockBase;
  466.  
  467.         TrueBlockBase = (BlockRec*)((char*)Block
  468.             - ((char*)&(((BlockRec*)NIL)->Next) - (char*)NIL));
  469.         APRINT(("*BlockSize %r %l",Block,DECODEREQUESTEDSIZE(TrueBlockBase->BlockSize)));
  470.         return DECODEREQUESTEDSIZE(TrueBlockBase->BlockSize);
  471.     }
  472.  
  473.  
  474. /* resize the block.  Minimum of the new size and the old size bytes of data will */
  475. /* be preserved.  NOTE:  The block's address may change!!! */
  476. /* this is a very naive implementation which simply allocates a new block, copies */
  477. /* over all the data, and releases the old block.  For performance reasons, this */
  478. /* might be improved to intelligently look for a free block adjacent to the */
  479. /* allocated block.  However, by always relocating the block, it is very good at */
  480. /* pointing out bugs that assume blocks don't move when resized. */
  481. void*                BlockResize(void* Block, long NewRequestedBlockSize)
  482.     {
  483.         void*                NewPointer;
  484.         long                ValidSectionSize;
  485.         long                OldBlockSize;
  486.  
  487.         APRINT(("+BlockResize %r",Block));
  488.         ERROR((NewRequestedBlockSize < 0) || (NewRequestedBlockSize > MEMBLOCKLIMIT),
  489.             PRERR(ForceAbort,"BlockSize:  allocation block size is out of range"));
  490.         NewPointer = BlockNew(NewRequestedBlockSize);
  491.         if (NewPointer == NIL)
  492.             {
  493.                 return NIL;
  494.             }
  495.         OldBlockSize = BlockSize(Block);
  496.         if (NewRequestedBlockSize < OldBlockSize)
  497.             {
  498.                 ValidSectionSize = NewRequestedBlockSize;
  499.             }
  500.          else
  501.             {
  502.                 ValidSectionSize = OldBlockSize;
  503.             }
  504.         CopyData((char*)Block,(char*)NewPointer,ValidSectionSize);
  505.         BlockRelease(Block);
  506.         APRINT(("-BlockResize %r",NewPointer));
  507.         return NewPointer;
  508.     }
  509.  
  510.  
  511. /* scan list and look for inconsistencies, such as overlapping blocks, blocks */
  512. /* outside of the range of the heap, misaligned blocks, and other weirdness */
  513. /* this routine only does something when debugging is enabled */
  514. #if DEBUG
  515. void                CheckHeap(void)
  516.     {
  517.         BlockRec*        Scan;
  518.         BlockRec*        Lag;
  519.         Zone*                Zone;
  520.         char*                ZoneBeginning;
  521.         char*                ZoneEnd;
  522.  
  523.         APRINT(("+CheckHeap"));
  524.         if (AllocationCount < 0)
  525.             {
  526.                 PRERR(ForceAbort,"CheckHeap:  Number of allocated blocks is negative");
  527.             }
  528.         Lag = NIL;
  529.         Scan = FreeList;
  530.         Zone = GetZone();
  531.         ZoneBeginning = (char*)Zone;
  532.         ZoneEnd = (char*)(Zone->bkLim);
  533.         while (Scan != NIL)
  534.             {
  535.                 if (((unsigned long)Scan & (ALIGNMENT - 1)) != 0)
  536.                     {
  537.                         PRERR(ForceAbort,"CheckHeap:  Bad link pointer encountered");
  538.                     }
  539.                 if ((Scan->BlockSize & (ALIGNMENT - 1)) != 0)
  540.                     {
  541.                         PRERR(ForceAbort,"CheckHeap:  Misaligned free block size value");
  542.                     }
  543.                 if (((char*)Scan < ZoneBeginning) || ((char*)Scan >= ZoneEnd))
  544.                     {
  545.                         PRERR(ForceAbort,"CheckHeap:  Reference is outside heap area!");
  546.                     }
  547.                 if (Scan->BlockSize < sizeof(BlockRec))
  548.                     {
  549.                         PRERR(ForceAbort,"CheckHeap:  Free block's size is too small");
  550.                     }
  551.                 if (Scan <= Lag)
  552.                     {
  553.                         PRERR(ForceAbort,"CheckHeap:  Block occurs lower than previous block");
  554.                     }
  555.                 if ((Scan->Next != NIL) && ((char*)Scan + Scan->BlockSize >= (char*)(Scan->Next)))
  556.                     {
  557.                         PRERR(ForceAbort,"CheckHeap:  Block + Size overshoots next block");
  558.                     }
  559.                 Scan = Scan->Next;
  560.             }
  561.         APRINT(("-CheckHeap"));
  562.     }
  563. #endif
  564.  
  565.  
  566. /* this routine dumps a file to the working directory containing a list of the */
  567. /* free blocks in the heap so that fragmentation performance can be analyzed */
  568. /* this routine only does something when debugging is enabled */
  569. #if DEBUG
  570. void                CheckFragmentation(void)
  571.     {
  572.         BlockRec*            Scan;
  573.         char                    DumpName[] = "\p!!HeapFragmentationDump";
  574.         static char        Hex[] = "0123456789abcdef";
  575.         short                    MemDumpFile;
  576.         char                    NumAllocatedBlocks[] = "Number of allocated blocks = xxxxxxxx\x0d";
  577.         long                    Index;
  578.  
  579.         FSDelete((unsigned char*)DumpName,0);
  580.         ERROR(Create((unsigned char*)DumpName,0,AUDITCREATOR,'TEXT') != noErr,
  581.             PRERR(ForceAbort,"Couldn't create fragmentation dump file"));
  582.         ERROR(FSOpen((unsigned char*)DumpName,0,&MemDumpFile) != noErr,PRERR(ForceAbort,
  583.             "Couldn't open fragmentation dump file for writing"));
  584.         for (Index = 0; Index < 8; Index += 1)
  585.             {
  586.                 NumAllocatedBlocks[29 + Index]
  587.                     = Hex[(AllocationCount >> ((7 - Index) * 4)) & 0x0f];
  588.             }
  589.         Index = 38;
  590.         FSWrite(MemDumpFile,&Index,NumAllocatedBlocks);
  591.         Scan = FreeList;
  592.         while (Scan != NIL)
  593.             {
  594.                 char                        Buffer[] = "xxxxxxxx..xxxxxxxx (xxxxxxxx)\x0d";
  595.                 long                        ByteCount = 30;
  596.                 unsigned long        Low;
  597.                 unsigned long        High;
  598.  
  599.                 Low = (unsigned long)Scan;
  600.                 High = Low + Scan->BlockSize - 1;
  601.                 for (Index = 0; Index < 8; Index += 1)
  602.                     {
  603.                         Buffer[Index] = Hex[(Low >> ((7 - Index) * 4)) & 0x0f];
  604.                     }
  605.                 for (Index = 0; Index < 8; Index += 1)
  606.                     {
  607.                         Buffer[Index + 10] = Hex[(High >> ((7 - Index) * 4)) & 0x0f];
  608.                     }
  609.                 for (Index = 0; Index < 8; Index += 1)
  610.                     {
  611.                         Buffer[Index + 20] = Hex[(Scan->BlockSize >> ((7 - Index) * 4)) & 0x0f];
  612.                     }
  613.                 FSWrite(MemDumpFile,&ByteCount,Buffer);
  614.                 Scan = Scan->Next;
  615.             }
  616.         FSClose(MemDumpFile);
  617.     }
  618. #endif
  619.